/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
 *
 * Zhiqim UI is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
 
+(function(Z)
{
/**************************************************/
//定义浏览器类型
/**************************************************/

Z.B = Z.Browser = 
{
    mobile: /mobile/.test(Z.ua),
    iphone: /iphone/.test(Z.ua),
    ipad: /ipad/.test(Z.ua),
    win64: /wow64/.test(Z.ua),
    firefox: /firefox/.test(Z.ua),
    webkit: /webkit/.test(Z.ua),
    safari: /safari/.test(Z.ua),
    chrome: /chrome/.test(Z.ua),
    opera: /opera/.test(Z.ua),
    mozilla: /mozilla/.test(Z.ua) && !/compatible/.test(Z.ua),
    msie: (/msie/.test(Z.ua) || /trident/.test(Z.ua)) && !/opera/.test(Z.ua),
    msieOnly: /msie/.test(Z.ua),
    msie11: /trident\/7/.test(Z.ua),
    msie10: /msie 10/.test(Z.ua),
    msie9: /msie 9/.test(Z.ua),
    msie8: /msie 8/.test(Z.ua),
    msie7: /msie 7/.test(Z.ua),
    msie6: /msie 6/.test(Z.ua),
    msieVer: /msie/.test(Z.ua)?parseInt(Z.ua.match(/msie (\d+)/)[1]):100
};

if (Z.B.msieVer <= 8)
{//IE8以内创建HTML5新规定的元素
    var html5ne = ["abbr", "article", "aside", "datalist", "details", "dialog", "eventsource", "figure", "footer", "header", "hgroup", 
                   "main", "mark", "menu", "meter", "nav", "output", "progress", "section", "time", 
                   "audio", "canvas", "video"];
    var nei= html5ne.length;
    while (nei--){
        document.createElement(html5ne[nei]);
    }
}

/**************************************************/
//定义文档和节点相关方法
/**************************************************/
Z.D = Z.Document = 
{
    id: function(id, doc)
    {
        doc = doc || document;
        return doc.getElementById(id);
    },
    has: function(id, doc)
    {
        doc = doc || document;
        return doc.getElementById(id) != null;
    },
    create: function(tag, doc)
    {
        doc = doc || document;
        return doc.createElement(tag);
    },
    names: function(name, doc)
    {
        doc = doc || document;
        return doc.getElementsByName(name);
    },
    tagNames: function(name, doc)
    {
        doc = doc || document;
        return doc.getElementsByTagName(name);
    },
    classNames: function(name, doc)
    {
        doc = doc || document;
        if (doc.getElementsByClassName)
        {//支持方法
            return doc.getElementsByClassName(name);
        }
        
        var elems = [];
        Z.each(this.tagNames("*"), function(elem)
        {
            Z.each(elem.className.split(" "), function(clazz)
            {
                if (clazz == name){
                    elems.push(elem);
                }
            });
        });
        return elems;
    },
    attrs: function(name, value, doc)
    {
        doc = doc || document;
        var elems = [];
        Z.each(this.tagNames("*"), function(elem)
        {
            if (value == Z.EL.get(elem, name)){
                elems.push(elem);
            }
        });
        return elems;
    },
    scrollTop: function(doc)
    {
        doc = doc || document;
        return doc.body.scrollTop + doc.documentElement.scrollTop;
    },
    scrollLeft: function(doc)
    {
        doc = doc || document;
        return doc.body.scrollLeft + doc.documentElement.scrollLeft;
    },
    scrollWidth: function(doc)
    {//可滚动展示宽度=(clientWidth<offsetWidth)?offsetWidth:clientWidth;
        doc = doc || document;
        return Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth);
    },
    scrollHeight: function(doc)
    {//可滚动展示高度=(clientHeight<offsetHeight)?offsetHeight:clientHeight;
        doc = doc || document;
        return Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight);
    },
    clientWidth: function(doc)
    {//窗口可视宽度（看得见的宽度）
        doc = doc || document;
        return doc.documentElement.clientWidth || doc.body.clientWidth;
    },
    clientHeight: function(doc)
    {//窗口可视高度（看得见的宽度）
        doc = doc || document;
        return doc.documentElement.clientHeight || doc.body.clientHeight;
    },
    offsetWidth: function(doc)
    {//可操作宽度（由元素决定，和窗口无关）
        doc = doc || document;
        return Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth);
    },
    offsetHeight: function(doc)
    {//可操作高度（由元素决定，和窗口无关）
        doc = doc || document;
        return Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight);
    },
    clearSelection: function()
    {//清除选中区域
        window.getSelection?window.getSelection().removeAllRanges():document.selection.empty();
    }
};

/**************************************************/
//定义事件的增删等操作
/**************************************************/
Z.E = Z.Event = 
{
    KEY: {
        ESC: 27, ENTER: 13,
        LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, DELETE: 46
    },
    add: function(target, name, listener, $this) 
    {
        listener = $this?Z.bind(listener, $this):listener;
        if (target.addEventListener){
            target.addEventListener(name, listener, false);
        }else if (target.attachEvent){
            target.attachEvent("on"+name, listener);
        }else{
            target["on"+name] = listener;
        }
    },
    remove: function(target, name, listener, $this) 
    {
        listener = $this?Z.bind(listener, $this):listener;
        if (target.removeEventListener){
            target.removeEventListener(name, listener, false);
        }else if (target.detachEvent){
            target.detachEvent("on"+name, listener);
        }else{
            target["on"+name] = null;
        }
    },
    event: function(e)
    {
        return e || window.event;
    },
    key: function(e)
    {
        e = this.event(e);
        return e.which || e.keyCode;
    },
    target: function(e)
    {
        e = this.event(e);
        return e.target || e.srcElement;
    },
    current: function(e)
    {
        e = this.event(e);
        return e.currentTarget || e.srcElement;
    },
    cancel: function(e)
    {//取消缺省事件，如form.submit事件时，可取消submit缺省的动作
        if (e && e.preventDefault){
            e.preventDefault();
        }else if (window.event){
            window.event.returnValue = false;
        }
        return false;
    },
    stop: function(e)
    {//停止冒泡，冒泡事件从里到外，如<div id="1"><div id="2"></div></div>中点击事件，id=2事件时stop，则id=1的id就不会被触发
        if (e && e.stopPropagation){
            e.stopPropagation();
        }else if (window.event){
            window.event.cancelBubble = true;
        }
        return false;
    },
    forbidden: function(e)
    {//停止冒泡和取消缺省事件
        Z.E.stop(e);
        Z.E.cancel(e);
    },
    
    clientX: function(e)
    {//点击位置相对于浏览器的X坐标
        return this.event(e).clientX;
    },
    clientY: function(e)
    {//点击位置相对于浏览器的Y坐标
        return this.event(e).clientY;
    },
    screenX: function(e)
    {//点击位置相对于屏幕的X坐标
        return this.event(e).clientX;
    },
    screenY: function(e)
    {//点击位置相对于屏幕的Y坐标
        return this.event(e).clientY;
    },
    wheelDelta: function(e)
    {//滚轮增量
        return Z.B.firefox?(-this.event(e).detail*40):this.event(e).wheelDelta;
    },
    /***************************************************/
    //判断按键，支持退格,复制粘贴等
    /***************************************************/
    isCtrl: function(e)
    {//按住控制键
        return Z.E.event(e).ctrlKey;
    },
    isEsc: function(e)
    {//退出
        return Z.E.key(e) === 27;
    },
    isBackspace: function(e)
    {//退格
        return Z.E.key(e) === 8;
    },
    isEnter: function(e)
    {//回车
        return Z.E.key(e) === 13;
    },
    isCtrlC: function(e)
    {//Ctrl+C
        return Z.E.isCtrl(e) && Z.E.key(e) == 67;
    },
    isCtrlV: function(e)
    {//Ctrl+V
        return Z.E.isCtrl(e) && Z.E.key(e) == 86;
    }
};

/**************************************************/
//定义元素操作
/**************************************************/
Z.EL = Z.Element = 
{
    PX:["top", "bottom", "left", "right", "width", "height", 
        "min-width", "max-width", "min-height", "max-height", "line-height", "text-indent",
        "minWidth", "maxWidth", "minHeight", "maxHeight", "lineHeight", "textIndent",
        "margin-top", "margin-bottom", "margin-left", "margin-right", "padding-top", "padding-bottom", "padding-left", "padding-right", "font-size",
        "marginTop", "marginBottom", "marginLeft", "marginRight", "paddingTop", "paddingBottom", "padding-Left", "paddingRight", "fontSize"],
    has: function(elem, name)
    {//是否有属性
        if (!elem || !elem.nodeType)
            return false;
            
        if (name in elem)
            return true;
        else if (elem.hasAttribute && elem.hasAttribute(name))
            return true;
        return false;
    },
    get: function(elem, name)
    {//获取属性
        if (!elem || !elem.nodeType)
            return null;
            
        if (name in elem)
            return elem[name];
        else if (elem.getAttribute)
            return elem.getAttribute(name);
        return null;
    },
    set: function(elem, name, value)
    {//设置属性
        if (!elem || !elem.nodeType)
            return;

        if (name in elem)
            elem[name] = value;
        else if (elem.setAttribute)
            elem.setAttribute(name, value);
    },
    equals: function(elem, name, value)
    {//判断属性值是否等于指定值
        if (!elem || !elem.nodeType)
            return false;
            
        return Z.EL.get(elem, name) == value;
    },
    style: function(elem, style)
    {//设置样式
        if (!this.has(elem, "style"))
            return;
        
        if (style === Z.u){//未传参数
            return elem.style;
        }

        var obj = Z.AR.toObject(style, ";");
        for (var key in obj){
            elem.style[key] = obj[key];
        }
    },
    css: function(elem, name, value)
    {//读样式或写样式
        if (!this.has(elem, "style"))
            return;
            
        if (name == "opacity")
        {//opacity单独对待
            return this.opacity(elem, value);
        }
            
        if (arguments.length == 2)
        {//2个参数时表示读参数
            if (elem.style[name]){
                return elem.style[name];
            }
            
            if (elem.currentStyle){
                return elem.currentStyle[name];
            }
            
            if (document.defaultView){
                return document.defaultView.getComputedStyle(elem, null)[name];
            }
            
            return "";
        }
        else if (arguments.length == 3)
        {//3个参数时表示写参数
            //检查top,bottom,left,right,width,height支持数字
            if (Z.AR.contains(Z.EL.PX, name)){
                value = (Z.T.isNumber(value) || Z.V.isInteger(value) || Z.V.isFloat(value))?value+"px":value;
            }
            elem.style[name] = value;
        }
    },
    cssNum: function(elem, name)
    {
        return Z.S.prefixNum(this.css(elem, name));
    },
    opacity: function(elem, value)
    {
        if (!this.has(elem, "style"))
            return;
            
        if (value === Z.u)
        {
            if ("opacity" in elem.style){
                return elem.style.opacity?parseFloat(elem.style.opacity):0;
            }else{
                var filter = elem.style["filter"];
                var opMatch = (!filter)?null:filter.match(/opacity=([\d.]*)[\)\,\s]/i);
                if (!opMatch || opMatch.length < 2)
                    return 0;
                    
                return opMatch[1] / 100;
            }
        }
        else if (Z.T.isNumber(value) || Z.V.isFloat(value))
        {//数字或者数字型字符串
            value = +value;
            if ("opacity" in elem.style){
                elem.style.opacity = value;
            }else{
                elem.style["filter"] = "alpha(opacity=" + value*100 + ")";
            }
        }
    },
    className: function(elem, className)
    {
        if (!this.has(elem, "className"))
            return null;
        
        if (className === Z.u){//未传参数
            return elem.className;
        }
        
        elem.className = className;
    },
    addClass: function(elem, className)
    {
        if (!this.has(elem, "className"))
            return;
        
        var classArr = Z.AR.toArray(elem.className, Z.R.SPACE);
        if (Z.AR.contains(classArr, className))
            return;
            
        classArr.push(className);
        elem.className = Z.AR.toString(classArr, " ");
    },
    removeClass: function(elem, className)
    {//abc def hjk   def hjk
        if (!this.has(elem, "className"))
            return;
        
        var classArrRemove = Z.AR.toArray(className, Z.R.SPACE);
        var classNameElem = " " + elem.className.replace(/\s\s/g, " ") + " ";//_abc_def_hjk_
        classArrRemove.map(function(clName)
        {
            clName = " " + clName.trim() + " ";//_def_
            if (classNameElem.indexOf(clName) === -1)
                return;
            classNameElem = classNameElem.replace(clName, " ").replace(/\s\s/g, " ");//_abc_hjk_
        });
        elem.className = classNameElem.trim();//abc
    },
    hasClass: function(elem, className)
    {
        if (!this.has(elem, "className"))
            return false;
            
        var classArr = Z.AR.toArray(elem.className, Z.R.SPACE);
        return Z.AR.contains(classArr, className);
    },
    toggleClass: function(elem, className)
    {
        this.hasClass(elem, className)?this.removeClass(elem, className):this.addClass(elem, className);
    },
    select: function(elem)
    {
        if (!elem || !elem.nodeType)
            return;
        elem.select();
    },
    selection: function(elem)
    {
        if (!this.has(elem, "value"))
            return "";
        
        var value = this.get(elem, "value");
        if (Z.V.isEmpty(value))
            return "";
            
        if (!("selectionStart" in elem))
            return "";
            
        var start = elem.selectionStart;
        var end = elem.selectionEnd;
        return value.substring(start, end);
    },
    isSelection: function(elem)
    {
        return Z.V.isNotEmpty(this.selection(elem));
    },
    focus: function(elem)
    {
        if (!elem || !elem.nodeType)
            return;
        elem.focus();
    },
    focusEnd: function(elem, len)
    {//元素焦点捕捉
        if (!elem || !elem.nodeType)
            return;
            
        len = len || 0;
        if (Z.B.msieOnly)
        {
            var range = elem.createTextRange();
            (len == 0)?range.collapse(false):range.move("character", len);
            range.select();
        }
        else
        {
            len = (len == 0)?elem.value.length:len;
            elem.setSelectionRange(len, len);
            elem.focus();
        }
    },
    parent: function(elem) 
    {//元素父元素
        if (!elem || !elem.nodeType)
            return null;
            
        var parent = elem.parentNode;
        return parent && parent.nodeType !== 11 ? parent : null;
    },
    parentIndex: function(elem)
    {//元素子节点在父元素的索引
        var ind = 0;
        while(elem = elem.previousSibling){
            if (elem.nodeType == 1)
                ind++;
        }
        return ind;
    },
    childs: function(elem)
    {//元素子节点
        if (!elem || !elem.nodeType)
            return null;
            
        return elem.childNodes;
    },
    children: function(elem)
    {//元素子元素
        if (!elem || !elem.nodeType)
            return null;
            
        return elem.children;
    },
    html: function(elem, value)
    {//设置元素HTML代码或获取HTML代码
        if (!elem || !elem.nodeType)
            return;
        
        if (value === Z.u)
            return elem.innerHTML;
        else
            elem.innerHTML = value;
    },
    htmls: function(elem, value)
    {//替换元素或获取outerHTML代码
        if (!elem || !elem.nodeType)
            return;
        
        if (value === Z.u)
            return elem.outerHTML;
        else
            elem.outerHTML = value;
    },
    htmlc: function(elem, value)
    {//设置元素HTML代码或获取HTML代码
        if (!elem || !elem.nodeType)
            return;
        
        if (value === Z.u)
            return elem.innerHTML;
        
        elem.innerHTML = value;
        
        //1.八项指定内容加载，其中四项是相对定位
        if (Z.Input && Z.Input.load)
        {//输入框验证
            Z.Input.load(elem);
        }
        
        if (Z.ButtonGroup && Z.ButtonGroup.load)
        {//按钮组
            Z.ButtonGroup.load(elem);
        }
        
        if (Z.Checkbox && Z.Checkbox.load)
        {//多选按钮
            Z.Checkbox.load(elem);
        }
        
        if (Z.Radio && Z.Radio.load)
        {//单选按钮
            Z.Radio.load(elem);
        }
        
        if (Z.Select && Z.Select.load)
        {//选择框
            Z.Select.load(elem);
        }
        
        if (Z.Dropdown && Z.Dropdown.load)
        {//下拉列表
            Z.Dropdown.load(elem);
        }
    
        if (Z.Textarea && Z.Textarea.load)
        {//选择框
            Z.Textarea.load(elem);
        }
        
        if (Z.CallFrame && Z.CallFrame.load)
        {//表单iframe调用
            Z.CallFrame.load();
        }
        
        //2.两项全局更新的，AJAX内容会影响外部布局
        if (Z.Tooltip && Z.Tooltip.load)
        {//提示框
            Z.Tooltip.load();
        }
        
        if (Z.Clipboard && Z.Clipboard.onload)
        {//复制按钮
            Z.Clipboard.onload();
        }
                
        //3.判断是否有<script></script>要求处理
        var $allScript = elem.querySelectorAll('script');
        for (var i=0;i<$allScript.length;i++)
        {
            // 获取 js 代码
            var $script = $allScript[i];
            var jsString = $script.innerHTML;
            var jsSrc = $script.getAttribute('src');
            
            // 判断是引入还是书写
            if (Z.V.isEmptyBlank(jsString) && (jsSrc === null || Z.V.isEmptyBlank(jsString)))
                continue;
            
            // 定义新 script 节点
            var $newScript = document.createElement('script');
            
            // 赋值 script 的属性值
            var attrs = $script.attributes;
            for (var j=0;j<attrs.length;j++) {
                $newScript[attrs[j].name] = attrs[j].value;
            }
            $newScript.innerHTML = jsString;
            $script.insertAdjacentElement('afterend', $newScript);
            
            // 删除原有 script 节点
            $script.parentNode.removeChild($script);
        }
    },
    text: function(elem, value)
    {//设置元素文本或获取文件
       if (!elem || !elem.nodeType)
            return;
       
       if (value === Z.u)
       {
            if (this.has(elem, "innerText"))
                return elem.innerText;
            else
                return elem.textContent;
        }
        else
        {
            if (this.has(elem, "innerText"))
                elem.innerText = value;
            else
                elem.textContent = value;
        }
    },
    append: function(elem, child)
    {
        if (!elem || !elem.nodeType)
            return;

        if (Z.T.isElement(child))
            return elem.appendChild(child);
        else if (Z.T.isString(child))
            elem.insertAdjacentHTML("beforeend", child);
    },
    prepend: function(elem, child)
    {
        if (!elem || !elem.nodeType || elem.nodeType != 1)
            return;

        if (Z.T.isElement(child))
            return elem.insertBefore(child, elem.firstNode);
        else if (Z.T.isString(child))
            elem.insertAdjacentHTML("afterbegin", child);
    },
    before: function(elem, newElem)
    {
        if (!elem || !elem.nodeType || !elem.parentNode)
            return;

        if (Z.T.isElement(newElem))
            elem.parentNode.insertBefore(newElem, elem);
        else if (Z.T.isString(newElem))
            elem.insertAdjacentHTML("beforebegin", newElem);
    },
    after: function(elem, newElem)
    {
        if (!elem || !elem.nodeType || !elem.parentNode)
            return;
        
        if (Z.T.isElement(newElem))
            elem.parentNode.insertBefore(newElem, elem.nextSibling);
        else if (Z.T.isString(newElem))
            elem.insertAdjacentHTML("afterend", newElem);
    },
    replace: function(elem, newElem)
    {
        if (!elem || !elem.nodeType || !elem.parentNode)
            return;
            
        elem.parentNode.replaceChild(newElem, elem);
    },
    remove: function(elem, name)
    {
        if (!elem || !elem.nodeType)
            return;
            
        if (!name)
        {//删除节点
            var parentNode = elem.parentNode;
            if (parentNode != null)
                parentNode.removeChild(elem);
        }
        else
        {//删除属性
            if (elem.hasAttribute(name))
                elem.removeAttribute(name);
            else
                elem[name] = "";
        }
    },
    offsetLeft: function(elem)
    {
        return (!Z.B.firefox)?elem.offsetLeft:this.offsetFirefox(elem, "offsetLeft", "borderLeftWidth");
    },
    offsetTop: function(elem)
    {
        return (!Z.B.firefox)?elem.offsetTop:this.offsetFirefox(elem, "offsetTop", "borderTopWidth");
    },
    offsetLeftBody: function(elem)
    {
        if (Z.B.webkit)
            return this.offsetBodyWebkit(elem, "offsetLeft", "borderLeftWidth");
        else if (Z.B.msieVer <= 8)
            return this.offsetBodyIE(elem, "offsetLeft", "borderLeftWidth");
        else
            return this.offsetBodyFirefox(elem, "offsetLeft");
    },
    offsetTopBody: function(elem)
    {
        if (Z.B.webkit)
            return this.offsetBodyWebkit(elem, "offsetTop", "borderTopWidth");
        else if (Z.B.msieVer <= 8)
            return this.offsetBodyIE(elem, "offsetTop", "borderTopWidth");
        else
            return this.offsetBodyFirefox(elem, "offsetTop");
    }
};

/**************************************************/
//定义元素私有方法
/**************************************************/
Z.EL.siblingByTd = function(td, type)
{
    if ("offsetLeft" == type)
    {//找左边TD
        var sibling = td.previousSibling;
        if (sibling instanceof Text)
            sibling = td.previousSibling.previousSibling;
        return sibling;
    }
    else
    {//找上边TD
        var ind = this.parentIndex(td);
        var parentElem = td.parentNode;
        var sibling = parentElem.previousSibling;
        if (sibling instanceof Text)
            sibling = parentElem.previousSibling.previousSibling;
        if (sibling)
            return sibling.childNodes[ind];
        return sibling;
    }
};
Z.EL.offsetFirefox = function(elem, type, border)
{
    var td = elem.offsetParent;
    if (!(td instanceof HTMLTableCellElement) || this.css(td, "borderCollapse") === "separate")
    {//不是表格单元格或表格边框是分隔的，直接减去边框
        return elem[type] - this.cssNum(td, border);
    }
    
    //表格单元格边框是合并的情况，取自己边框或相邻边框或表格边框最大值
    var tdBorderWidth = this.cssNum(td, border);
    var tbBorderWidth = this.cssNum(td.offsetParent, border);
    var cssName = ("offsetLeft" == type)?"borderRightWidth":"borderBottomWidth";
    
    var sibling = this.siblingByTd(td, type);
    var sbBorderWidth = sibling?this.cssNum(sibling, cssName):tbBorderWidth;
    return elem[type] - Math.max(tdBorderWidth, sbBorderWidth);
};
    
Z.EL.offsetBodyFirefox = function(elem, type, border)
{//火狐最简单
    var value = elem[type];
    while(elem.offsetParent && elem.offsetParent.tagName != "BODY" && elem.offsetParent.tagName != "HTML")
    {
        elem = elem.offsetParent;
        value += elem[type];
        if (border){
            value += Z.S.prefixNum(this.css(elem, border));
        }
    }
    if (Z.EL.css(elem,"position") == "fixed")
    {//定位为fixed的情况
        if (type == "offsetLeft"){
            value += Z.body().scrollLeft + document.documentElement.scrollLeft;
        } else if (type == "offsetTop"){
            value += Z.body().scrollTop + document.documentElement.scrollTop;
        }
    }
    return value;
};

Z.EL.offsetBodyIE = function(elem, type, border)
{//IE较复杂：1.标记有定位的需要增加边框
    if (!(elem.offsetParent instanceof HTMLTableCellElement))
    {//不在表格中
        return this.offsetBodyFirefox(elem, type, border);
    }
    
    var cssName = ("offsetLeft" == type)?"borderRightWidth":"borderBottomWidth";
    var value = elem[type];
    var elem = elem.offsetParent;
    while(elem)
    {
        value += elem[type];
        if (!(elem instanceof HTMLTableCellElement))
        {//不是单元格直接增加边框
            value += Z.S.prefixNum(this.css(elem, border));
            elem = elem.offsetParent;
            continue;
        }
        
        //表格单元格
        var borderCollapse = this.css(elem.offsetParent, "borderCollapse");
        var tdBorderWidth = this.cssNum(elem, border);
        
        if (borderCollapse == "separate")
        {//单元格边框不合并，只计算自己的边框即可
            value += tdBorderWidth;
        }
        else
        {//单元格边框是合并的，需要检查对面的边框，取边框和对面边框最大值的1/2。如果靠最左最上则为本身边框和表格边框最大值的1/2
            var tbBorderWidth = this.cssNum(elem.offsetParent, border);
            var sibling = this.siblingByTd(elem, type);
            var sbBorderWidth = sibling?this.cssNum(sibling, cssName):tbBorderWidth;
            value += Math.max(tdBorderWidth, sbBorderWidth) / 2;
        }
        
        value += elem.offsetParent[type];
        elem = elem.offsetParent.offsetParent;
    }

    return value;
};

Z.EL.offsetBodyWebkit = function(elem, type, border)
{//webkit
    if (!(elem.offsetParent instanceof HTMLTableCellElement))
    {//不在表格中
        return this.offsetBodyFirefox(elem, type, border);
    }
    
    var cssName = ("offsetLeft" == type)?"borderRightWidth":"borderBottomWidth";
    var value = elem[type];
    var elem = elem.offsetParent;
    while(elem)
    {
        value += elem[type];
        if (!(elem instanceof HTMLTableCellElement))
        {//不是单元格直接增加边框
            value += this.cssNum(elem, border);
            elem = elem.offsetParent;
            continue;
        }
        
        //表格单元格
        var borderCollapse = this.css(elem.offsetParent, "borderCollapse");
        var tdBorderWidth = this.cssNum(elem, border);
        var tbBorderWidth = this.cssNum(elem.offsetParent, border);
        
        if (borderCollapse == "separate")
        {//单元格边框不合并，只计算自己的边框和表格边框即可
            value += tdBorderWidth;
            value += tbBorderWidth;
        }
        else
        {//单元格边框是合并的，需要检查对面的边框，取最大值的边框的1/2+表格边框的1/2。如果靠最左最上则为本身边框和表格边框的最大值
            var sibling = this.siblingByTd(elem, type);
            if (sibling){
                var sbBorderWidth = this.cssNum(sibling, cssName);
                value += Math.max(sbBorderWidth, tdBorderWidth) / 2;
                value += tbBorderWidth / 2;
            }else{
                value += Math.max(tdBorderWidth, tbBorderWidth);
            }
        }
        
        value += elem.offsetParent[type];
        elem = elem.offsetParent.offsetParent;
    }

    return value;
};

/*****************************************************************/
//定义HTML标签封装，1.通过HTML文本创建元素列表，2.查标签缺省display值
/*****************************************************************/
Z.H = Z.Html = 
{
    wrapMap:
    {
        option: [1, "<select multiple='multiple'>", "</select>"],
        optgroup: [1, "<select multiple='multiple'>", "</select>"],
        legend: [1, "<fieldset>", "</fieldset>"],
        thead: [1, "<table>", "</table>"],
        tbody: [1, "<table>", "</table>"],
        tfoot: [1, "<table>", "</table>"],
        colgroup: [1, "<table>", "</table>"],
        caption: [1, "<table>", "</table>"],
        tr: [2, "<table><tbody>", "</tbody></table>"],
        td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
        th: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
        col: [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"],
        area: [1, "<map>", "</map>" ],
        _default: [0, "", ""]
    },
    createElement: function(html)
    {//创建HTML节点，返回一个类数组，可能是数组或NodeList或HTMLCollection
    
        if (!html)
        {//1.参数无效返回空数组
            return [];
        }
        
        if (html.nodeType)
        {//2.本身是节点返回数组只包括本身
            return [html];
        }
            
        if (Z.T.isNumber(html))
        {//3.如果是数字转为字符串
            html += "";
        }
        
        if (!Z.T.isString(html))
        {//4.不是字符串不支持，返回空数组
            return [];
        }
        
        if (!Z.R.HTML.test(html))
        {//5.判断是否是HTML，如果不是则创建文本节点，返回数组包括本身
            return [document.createTextNode(html)];
        }
        
        //6.适配标签成XHTML样式，对如<br>, <input>等无结尾的</br>进行适配
        html = html.replace(Z.R.HTML_XHTML_TAG, "<$1></$2>");

        //7.读取标签，并根据标签查询标签需要的特殊封装层次，这一步很重要，如<tr>需要在<table><tbody>中，其他的在<div>中即可
        var tag = (Z.R.HTML_TAG_NAME.exec(html) || ["", ""])[1].toLowerCase(),
            wrap = Z.H.wrapMap[tag] || Z.H.wrapMap._default,
            depth = wrap[0],
            div = document.createElement("div");

        //8.把HTML加到定义的div节点上，再根据封装层次取出节点
        div.innerHTML = wrap[1] + html + wrap[2];
        while (depth--){
            div = div.lastChild;
        }

        return div.childNodes;
    },

    displayCache: {},
    displayDefault: function(tag)
    {//查询标签缺省的display值，查过之后存储到缓存中
        if (this.displayCache[tag])
        {//1.已有检查的返回
            return this.displayCache[tag];
        }
        
        //2.增加到body中查找是否能读取display
        var body = document.body;
        var elem = Z.D.create(tag);
        body.appendChild(elem);
        var display = Z.EL.css(elem, "display");
        body.removeChild(elem);
        
        if (display !== "" && display !== "none")
        {
            this.displayCache[tag] = display;
            return display;
        }
        
        //3.新建iframe中读取display
        var iframe = Z.D.create("iframe");
        iframe.frameBorder = iframe.width = iframe.height = 0;
        body.appendChild(iframe);
    
        var iframeDoc = (iframe.contentWindow || iframe.contentDocument ).document;
        iframeDoc.write((document.compatMode === "CSS1Compat"?"<!doctype html>":"") + "<html><body>");
        iframeDoc.close();
    
        elem = iframeDoc.createElement(tag);
        iframeDoc.body.appendChild(elem);
    
        display = this.css(elem, "display");
        body.removeChild(iframe);
    
        this.displayCache[tag] = display;
        return display;
    }
};

/**************************************************/
//定义地址的增删等操作
/**************************************************/
Z.L = Z.Location =
{
    protocol: location.href.match(/^https/i)?"https":"http",
    reload: function(target)
    {//刷新
        target = target || window;
        target.location.reload();
    },
    access: function(url, target)
    {//访问
        Z.A.assertNotEmptyBlank(url, "Z.Location的所有函数url不能为空");
        
        target = target || window;
        if (target === "open" || target === "blank")
        {
            var $a = Z("<a></a>").appendTo("body");
            $a.attr({"href": url, "target": "blank"})[0].click();
            $a.remove();
        }
        else if (target.name && target.name == "zCallFrame")
        {//Frame调用
            url += ((url.indexOf("?")==-1)?"?":"&") + "zCallFrame=true";
            target.location.href = url;
        }
        else
            target.location.href = url;
    },
    check: function(url, name, form, target)
    {//检查
        Z.A.assertNotEmptyBlank(url, "Z.Location的所有函数url不能为空");
        
        if (form)
        {//第三个参数，可选form/target
            if (!(form instanceof HTMLFormElement) && target == null)
            {
                target = form;
                form = null;
            }
        }
        
        var value = Z.FM.getChecked(name, form);
        if (!value)
            return;
            
        url += (url.indexOf("?")==-1)?"?":"&";
        url += name+"="+Z.encode(value);
        Z.L.access(url, target);
    },
    confirm: function(url, message, name, form, target)
    {//确认
        Z.A.assertNotEmptyBlank(url, "Z.Location的所有函数url不能为空");
        
        if (form)
        {//第四个参数，可选form/target
            if (!(form instanceof HTMLFormElement) && target == null)
            {
                target = form;
                form = null;
            }
        }
        
        if (name)
        {//有指定选择项，把选项名和值加到URL中
            var value = Z.FM.getChecked(name, form);
            if (!value)
                return;
                
            url += (url.indexOf("?")==-1)?"?":"&";
            url += name+"="+Z.encode(value);
        }
 
        Z.confirm(message, function(){
            Z.L.access(url, target);
        });
    },
    href: function(param, param2)
    {//多参数访问
        if (Z.T.isString(param))
        {//简单模式，两个参数和access一样
            Z.L.access(param, param2);
        }
        else if (Z.T.isPlainObject(param))
        {//对象模式，支持多参数
            var url = param.url || null;
            var message = param.message || null;
            var name = param.name || null;
            var form = param.form || null;
            var target = param2 || param.target || null;
            if (name == null)
                Z.L.access(url, target);
            else if (message == null)
                Z.L.check(url, name, form, target);
            else
                Z.L.confirm(url, message, name, form, target);
        }
        else
        {//仅支持字符串和线对象两种方式
            Z.alert("Z.L.href函数第一个参数必须是字符串或纯对象");
        }
    }
};

/**************************************************/
//定义Cookie相关方法
/**************************************************/
Z.CK = Z.Cookie = 
{
    all: function()
    {
        return document.cookie;
    },
    add: function(cookie)
    {//name, value, expires, path, domain, secure
        if (!cookie || !cookie.name || Z.V.isEmptyBlank(cookie.name))
            return;
        
        var name = escape(Z.S.trim(cookie.name));
        var value = escape(cookie.value || "");
        var ck = name + "=" + value;
        if (Z.T.isNumber(cookie.expires) || Z.V.isInteger(cookie.expires))
        {
            var date = new Date();
            date.setTime(date.getTime() + (+cookie.expires * 1000)); 
            ck += ";expires=" + date.toGMTString();
        }
        
        ck += (cookie.path)?";path=" + cookie.path:"";
        ck += (cookie.domain)?";domain=" + cookie.domain:"";
        ck += (cookie.secure===true)?";secure":"";
        document.cookie = ck;
    },
    remove: function(name)
    {
        var date = new Date();
        date.setTime(date.getTime() - 10 * 1000);
        document.cookie = name+"=value;expires=" + date.toGMTString(); 
    },
    get: function(name)
    {
        if (Z.V.isEmptyBlank(name))
            return "";
            
        name = escape(Z.S.trim(name));
        var cookies = document.cookie.split(";");
        for(var i=0;i<cookies.length;i++)
        {
            var cookie = cookies[i].split("=");
            if(Z.S.trim(cookie[0]) == name) 
                return unescape(cookie[1]);
        }
        
        return "";
    }
};

//END
})(zhiqim);